home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Pascal / Carl O's Term / Term.Pas < prev    next >
Pascal/Delphi Source File  |  1994-10-14  |  19KB  |  685 lines

  1. {From: "Carl O" <cro@br213mail.nrel.gov>}
  2. {Subject: Mac Serial I/O code}
  3. {}
  4. {Attached is my Mac serial code.  The program is a complete simple terminal}
  5. {emulator that used some popup menu buttons that I was experimenting with.}
  6. {You can just trash those if you like--the actual serial port code is what}
  7. {I think you are interested in.  Any questions, just ask.}
  8. {}
  9. {Carl R. Osterwald}
  10.  
  11. {Changes by Ingemar Ragnemalm:}
  12. {Changed RamSDOpen/RamSDClose to OpenDriver/CloseDriver.}
  13. {Removed or commented out some stuff that don't apply to Think Pascal.}
  14. {Changed some identifiers to get closer to the Mac standard.}
  15. {Added some minor GUI features like Apple menu and About box.}
  16.  
  17. program Term;
  18.  
  19.     uses
  20. {$IFC UNDEFINED THINK_PASCAL}
  21. {Change these to, for example, MPW interfaces.}
  22.         MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, OSErrTrap, 
  23. {$ENDC}
  24.         Serial;
  25.  
  26.     type
  27.         Pac2 = packed array[1..2] of char;
  28.         Pac64 = packed array[1..64] of char;
  29.  
  30.     const
  31.         kChanARcvAvail = 24;
  32.         menu_ID = 1;
  33.         aboutID = 128;
  34.         appleMenu_ID = 2;
  35.         baud_menu_ID = 235;
  36.         parity_menu_ID = 234;
  37.         quit_item = 1;
  38.         about_item = 1;
  39.         baud_300_item = 1;
  40.         baud_600_item = 2;
  41.         baud_1200_item = 3;
  42.         baud_1800_item = 4;
  43.         baud_2400_item = 5;
  44.         baud_3600_item = 6;
  45.         baud_4800_item = 7;
  46.         baud_7200_item = 8;
  47.         baud_9600_item = 9;
  48.         baud_19200_item = 10;
  49.         baud_57600_item = 11;
  50.         no_parity_item = 1;
  51.         even_parity_item = 2;
  52.         odd_parity_item = 3;
  53.         scroll_bar_width = 16;
  54.         indent = 4;
  55.         line_space = 11;
  56.         char_space = 6;
  57.         ascent = 9;
  58.         descent = 2;
  59.         loop_length = 16;
  60.         flash_interval = $00000010;
  61.         control_G = $07;
  62.         control_H = $08;
  63.         control_J = $0A;
  64.         control_M = $0D;
  65.  
  66.     var
  67.         appleMenu, menu: MenuHandle;
  68.         baud_menu: MenuHandle;
  69.         parity_menu: MenuHandle;
  70.         menu_choice: LongInt;
  71.         baud: integer;
  72.         parity: integer;
  73.         checked_baud: integer;
  74.         checked_parity: integer;
  75.         window_rectangle: Rect;
  76.         terminal_window: WindowPtr;
  77.         terminal_rectangle: Rect;
  78.         temp_rectangle: Rect;
  79.         temp_control: ControlHandle;
  80.         break_button: ControlHandle;
  81.         help_button: ControlHandle;
  82.         update_region: RgnHandle;
  83.         which_window: WindowPtr;
  84.         which_control: ControlHandle;
  85.         click_location: Point;
  86.         current_event: EventRecord;
  87.         finished: boolean;
  88.         cursor_visible: Boolean;
  89.         cursor_rectangle: Rect;
  90.         next_flash_time: LongInt;
  91.         xPos: integer;
  92.         yPos: integer;
  93.         received_char: char;
  94.         buffer_ptr: Ptr;
  95.         in_buffer: Pac64;
  96.         this_char: Pac2;
  97.         screen_line: string[80];
  98.         width: integer;
  99.         height: integer;
  100.         right_limit: integer;
  101.         bottom_limit: integer;
  102.         no_of_lines: integer;
  103.         index: integer;
  104.         limit: integer;
  105.         len: integer;
  106.         configuration_word: integer;
  107.         protocol_record: SerShk;
  108.         byte_count: LongInt;
  109.         num_string: Str255;
  110.  
  111.   {--------------------------------------------------------------------------}
  112.  
  113.     procedure ErrorHandler (theErr: OSErr);
  114.     begin
  115.         if theErr = noErr then
  116.             exit(ErrorHandler);
  117.         SysBeep(10);
  118.         ExitToShell; {Eller halt?}
  119.     end;
  120.  
  121.   {--------------------------------------------------------------------------}
  122.  
  123.     procedure ConfigureModemPort;
  124.  
  125.     begin { ConfigureModemPort }
  126.         case checked_baud of
  127.             baud_300_item: 
  128.                 baud := baud300;
  129.             baud_600_item: 
  130.                 baud := baud600;
  131.             baud_1200_item: 
  132.                 baud := baud1200;
  133.             baud_1800_item: 
  134.                 baud := baud1800;
  135.             baud_2400_item: 
  136.                 baud := baud2400;
  137.             baud_3600_item: 
  138.                 baud := baud3600;
  139.             baud_4800_item: 
  140.                 baud := baud4800;
  141.             baud_7200_item: 
  142.                 baud := baud7200;
  143.             baud_9600_item: 
  144.                 baud := baud9600;
  145.             baud_19200_item: 
  146.                 baud := baud19200;
  147.             baud_57600_item: 
  148.                 baud := baud57600;
  149.             otherwise
  150.                 baud := baud1200;
  151.         end; { case }
  152.         case checked_parity of
  153.             no_parity_item: 
  154.                 parity := noParity;
  155.             even_parity_item: 
  156.                 parity := evenParity;
  157.             odd_parity_item: 
  158.                 parity := oddParity;
  159.             otherwise
  160.                 parity := evenParity;
  161.         end; { case }
  162.         configuration_word := BitOr(BitOr(baud, data7), BitOr(parity, stop10));
  163.         ErrorHandler(SerReset(aInRefNum, configuration_word));
  164.         ErrorHandler(SerReset(aOutRefNum, configuration_word));
  165.         CheckItem(baud_menu, checked_baud, true);
  166.         CheckItem(parity_menu, checked_parity, true);
  167.     end; { ConfigureModemPort }
  168.  
  169.   {--------------------------------------------------------------------------}
  170.  
  171.     procedure ControlActionProcedure (which_control: ControlHandle; part_code: integer);
  172.         var
  173.             which_menu: integer;
  174.             which_item: integer;
  175.             menu_point: Point;
  176.             menu_width: integer;
  177.  
  178.     begin { ControlActionProcedure }
  179.         HLock(Handle(which_control));
  180.         with which_control^^ do
  181.             begin
  182.                 InsertMenu(MenuHandle(contrlRfCon), -1);
  183.                 CalcMenuSize(MenuHandle(contrlRfCon));
  184.                 menu_point.v := contrlRect.top;
  185.                 menu_point.h := contrlRect.left;
  186.                 LocalToGlobal(menu_point);
  187.                 menu_width := MenuHandle(contrlRfCon)^^.menuWidth + 2;
  188.                 with menu_point do
  189.                     menu_choice := PopUpMenuSelect(MenuHandle(contrlRfCon), v - 1, h - menu_width, contrlMax);
  190.                 DeleteMenu(contrlMin);
  191.                 which_menu := HiWord(menu_choice);
  192.                 which_item := LoWord(menu_choice);
  193.                 case which_menu of
  194.                     baud_menu_ID: 
  195.                         begin
  196.                             CheckItem(baud_menu, contrlValue, false);
  197.                             case which_item of
  198.                                 baud_300_item: 
  199.                                     baud := baud300;
  200.                                 baud_600_item: 
  201.                                     baud := baud600;
  202.                                 baud_1200_item: 
  203.                                     baud := baud1200;
  204.                                 baud_1800_item: 
  205.                                     baud := baud1800;
  206.                                 baud_2400_item: 
  207.                                     baud := baud2400;
  208.                                 baud_3600_item: 
  209.                                     baud := baud3600;
  210.                                 baud_4800_item: 
  211.                                     baud := baud4800;
  212.                                 baud_7200_item: 
  213.                                     baud := baud7200;
  214.                                 baud_9600_item: 
  215.                                     baud := baud9600;
  216.                                 baud_19200_item: 
  217.                                     baud := baud19200;
  218.                                 baud_57600_item: 
  219.                                     baud := baud57600;
  220.                                 otherwise
  221.                                     which_item := contrlValue;
  222.                             end; { case }
  223.                             CheckItem(baud_menu, which_item, true);
  224.                             checked_baud := which_item;
  225.                             ContrlValue := which_item;
  226.                             ConfigureModemPort;
  227.                         end;
  228.                     parity_menu_ID: 
  229.                         begin
  230.                             CheckItem(parity_menu, contrlValue, false);
  231.                             case which_item of
  232.                                 no_parity_item: 
  233.                                     parity := noParity;
  234.                                 even_parity_item: 
  235.                                     parity := evenParity;
  236.                                 odd_parity_item: 
  237.                                     parity := oddParity;
  238.                                 otherwise
  239.                                     which_item := contrlValue;
  240.                             end; { case }
  241.                             CheckItem(parity_menu, which_item, true);
  242.                             checked_parity := which_item;
  243.                             ContrlValue := which_item;
  244.                             ConfigureModemPort;
  245.                         end;
  246.                 end; { case }
  247.             end; { with }
  248.         HLock(Handle(which_control));
  249.     end; { ControlActionProcedure }
  250.  
  251.   {--------------------------------------------------------------------------}
  252.  
  253. {procedure RamSDOpen (whichPort: SPortSel): OSErr;}
  254.  
  255.     procedure InitializeModemPort;
  256.  
  257.         var
  258.             aInRefNumDummy, aOutRefNumDummy: integer;
  259.     begin { InitializeModemPort }
  260. {RamSDOpen changed to OpenDriver}
  261. {ErrorHandler(RamSDOpen(SPortA)); { open driver for modem port }
  262.  
  263. { A = modem port, B = printer port}
  264.         ErrorHandler(OpenDriver('.AIn', aInRefNumDummy));
  265.         ErrorHandler(OpenDriver('.AOut', aOutRefNumDummy));
  266.  
  267.         ConfigureModemPort;
  268.         with protocol_record do
  269.             begin
  270.                 fXon := 0;                      { Xon/Xoff for output disabled }
  271.                 fCTS := 0;                      { CTS handshake disabled }
  272.                 errs := 0;                      { don't bother with errors }
  273.                 evts := 0;                      { don't post status events }
  274.                 fInX := 0;                      { Xon/Xoff for input disabled }
  275.             end; { with }
  276.         ErrorHandler(SerHShake(aInRefNum, protocol_record));
  277.         ErrorHandler(SerHShake(aOutRefNum, protocol_record));
  278.         this_char[1] := ' ';
  279.     end; { InitializeModemPort }
  280.  
  281.   {--------------------------------------------------------------------------}
  282.  
  283.     procedure InitializeUserInterface;
  284.  
  285.     begin { intialize_user_interface }
  286. {$IFC UNDEFINED THINK_PASCAL}
  287.         InitGraf(@thePort);
  288.         InitFonts;
  289.         InitWindows;
  290.         InitMenus;
  291.         TEInit;
  292.         InitDialogs(nil);
  293. {$ENDC}
  294.         FlushEvents(everyEvent, 0);
  295.  
  296.         appleMenu := NewMenu(appleMenu_ID, concat(char($14)));
  297.         AppendMenu(appleMenu, 'About Term…;(-');
  298.         AddResMenu(appleMenu, 'DRVR');
  299.         InsertMenu(appleMenu, 0);
  300.  
  301.         menu := NewMenu(menu_ID, 'File');
  302.         AppendMenu(menu, 'Quit/Q');
  303.         InsertMenu(menu, 0);
  304.         baud_menu := NewMenu(baud_menu_ID, 'Baud');
  305.         AppendMenu(baud_menu, '300;600;1200;1800;2400;3600;4800;7200;9600;19200;57600;');
  306.         parity_menu := NewMenu(parity_menu_ID, 'Parity');
  307.         AppendMenu(parity_menu, 'None;Even;Odd');
  308.         DrawMenuBar;
  309.         width := 80 * char_space + scroll_bar_width + 2 * indent;
  310.         height := 25 * line_space + 2 * indent;
  311.         with window_rectangle do
  312.             begin
  313.                 top := 50;
  314.                 bottom := top + height;
  315.                 left := (screenBits.Bounds.right - screenBits.Bounds.left - width) div 2;
  316.                 right := left + width;
  317.             end; { with }
  318.         terminal_window := NewWindow(nil, window_rectangle, 'Dumb Terminal Emulation', true, noGrowDocProc, WindowPtr(-1), false, 0);
  319.         SetPort(terminal_window);
  320.         terminal_rectangle := GrafPtr(terminal_window)^.portRect;
  321.         ClipRect(terminal_rectangle);
  322.         InsetRect(terminal_rectangle, indent, indent);
  323.         with terminal_rectangle do
  324.             right := right - scroll_bar_width;
  325.         TextFont(Monaco);
  326.         TextSize(9);
  327.         TextMode(srcCopy);
  328.         xPos := indent;
  329.         yPos := indent + ascent;
  330.         right_limit := terminal_rectangle.right - 1;
  331.         no_of_lines := (terminal_rectangle.bottom - yPos) div line_space + 1;
  332.         bottom_limit := yPos + (no_of_lines - 1) * line_space - 1;
  333.         DrawGrowIcon(terminal_window);
  334.         with GrafPtr(terminal_window)^.PortRect do
  335.             begin
  336.                 PenPat(white);
  337.                 MoveTo(0, bottom - 15);
  338.                 LineTo(right - 16, bottom - 15);
  339.                 PenPat(black);
  340.             end; { with }
  341.  
  342.         with GrafPtr(terminal_window)^.portRect do
  343.             SetRect(temp_rectangle, right - 14, bottom - 29, right, bottom - 14);  { L T R B }
  344.         break_button := NewControl(terminal_window, temp_rectangle, 'FFFF80019105890F851D8039B871802182018321871186498E418C418401FFFF', true, 0, 0, 0, $AAC0, 0);                          { break button }
  345.  
  346.         with GrafPtr(terminal_window)^.portRect do
  347.             SetRect(temp_rectangle, right - 14, bottom - 44, right, bottom - 29);  { L T R B }
  348.         checked_parity := even_parity_item;
  349.         temp_control := NewControl(terminal_window, temp_rectangle, 'FFFF8001811D816183898D01F1098101A109811DA1018101A101F38187C1FFFF', true, checked_parity, parity_menu_ID, odd_parity_item, $AAC0, 0);                          { parity button }
  350.         CheckItem(parity_menu, checked_parity, true);
  351.         SetCRefCon(temp_control, LongInt(parity_menu));
  352.         SetCtlAction(temp_control, @ControlActionProcedure);
  353.  
  354.         with GrafPtr(terminal_window)^.portRect do
  355.             SetRect(temp_rectangle, right - 14, bottom - 59, right, bottom - 44);  { L T R B }
  356.         checked_baud := baud_300_item;
  357.         temp_control := NewControl(terminal_window, temp_rectangle, 'FFFF800181018101810180018001C023A025904980418081808181018101FFFF', true, checked_baud, baud_menu_ID, baud_57600_item, $AAC0, 0);                          { baud button }
  358.         CheckItem(baud_menu, checked_baud, true);
  359.         SetCRefCon(temp_control, LongInt(baud_menu));
  360.         SetCtlAction(temp_control, @ControlActionProcedure);
  361.  
  362.         with GrafPtr(terminal_window)^.portRect do
  363.             SetRect(temp_rectangle, right - 14, bottom - 74, right, bottom - 59);  { L T R B }
  364.         help_button := NewControl(terminal_window, temp_rectangle, 'FFFF800183C18FF18C31981998199819807981E181818181800181818181FFFF', true, 0, 0, 0, $AAC0, 0);                           { help button }
  365.  
  366.         MoveTo(xPos, yPos);
  367.         update_region := NewRgn;
  368.         screen_line := '';
  369.         next_flash_time := 0;
  370.         cursor_visible := false;
  371.         InitCursor;
  372.         finished := false;
  373.     end; { InitializeUserInterface }
  374.  
  375.   {--------------------------------------------------------------------------}
  376.  
  377.     procedure InvertCursor;
  378.  
  379.     begin { InvertCursor }
  380.         SetRect(cursor_rectangle, xPos - 1, yPos - 2, xPos + 6, yPos + 1);
  381.         InvertRect(cursor_rectangle);
  382.         cursor_visible := not cursor_visible;
  383.     end; { InvertCursor }
  384.  
  385.   {--------------------------------------------------------------------------}
  386.  
  387.     procedure HideTheCursor;
  388.  
  389.     begin { HideTheCursor }
  390.         if cursor_visible then
  391.             InvertCursor;
  392.         next_flash_time := TickCount + flash_interval;
  393.     end; { HideTheCursor }
  394.  
  395.   {--------------------------------------------------------------------------}
  396.  
  397.     procedure FlashCursor;
  398.         var
  399.             tick_count: LongInt;
  400.  
  401.     begin { FlashCursor }
  402.         tick_count := TickCount;
  403.         if tick_count > next_flash_time then
  404.             begin
  405.                 InvertCursor;
  406.                 next_flash_time := tick_count + flash_interval;
  407.             end;
  408.     end; { FlashCursor }
  409.  
  410.   {--------------------------------------------------------------------------}
  411.  
  412.     procedure Linefeed;
  413.  
  414.     begin { Linefeed }
  415.         HideTheCursor;
  416.         if yPos > bottom_limit then
  417.             ScrollRect(terminal_rectangle, 0, -line_space, update_region)
  418.         else
  419.             begin
  420.                 yPos := yPos + line_space;
  421.                 MoveTo(xPos, yPos);
  422.             end;
  423.     end; { Linefeed }
  424.  
  425.   {--------------------------------------------------------------------------}
  426.  
  427.     procedure CarriageReturn;
  428.  
  429.     begin { CarriageReturn }
  430.         HideTheCursor;
  431.         xPos := indent;
  432.         MoveTo(xPos, yPos);
  433.     end; { CarriageReturn }
  434.  
  435.   {--------------------------------------------------------------------------}
  436.  
  437.     procedure HandleMenuChoice;
  438.         var
  439.             which_menu: integer;
  440.             which_item: integer;
  441.  
  442.             curPort: GrafPtr;
  443.             str: Str255;
  444.  
  445.     begin { HandleMenuChoice }
  446.         which_menu := HiWord(menu_choice);
  447.         which_item := LoWord(menu_choice);
  448.         case which_menu of
  449.             appleMenu_ID: 
  450.                 case which_item of
  451.                     about_item: 
  452.                         if Alert(aboutID, nil) = 1 then
  453.                             ;
  454.                     otherwise
  455.                         begin
  456.                             GetPort(curPort);
  457.                             GetItem(appleMenu, which_item, str);
  458.                             if OpenDeskAcc(str) = 0 then
  459.                                 ;
  460.                             SetPort(curPort);
  461.                         end;
  462.                 end; { case }
  463.             menu_ID: 
  464.                 case which_item of
  465.                     quit_item: 
  466.                         finished := true;
  467.                 end; { case }
  468.         end; { case }
  469.         HiLiteMenu(0);
  470.     end; { HandleMenuChoice }
  471.  
  472.   {--------------------------------------------------------------------------}
  473.  
  474.     procedure CheckMousePosition;
  475.         var
  476.             stop_time: LongInt;
  477.  
  478.     begin { CheckMousePosition }
  479.         case FindWindow(current_event.where, which_window) of
  480.             inMenuBar: 
  481.                 begin
  482.                     menu_choice := MenuSelect(current_event.where);
  483.                     HandleMenuChoice;
  484.                 end;
  485.             inDrag: 
  486.                 begin
  487.                     if (which_window <> FrontWindow) and (BitAnd(current_event.modifiers, cmdKey) = 0) then
  488.                         SelectWindow(which_window);
  489.                     DragWindow(which_window, current_event.where, screenBits.bounds);
  490.                 end;
  491.             inContent: 
  492.                 begin
  493.                     click_location := current_event.where;
  494.                     GlobalToLocal(click_location);
  495.                     if FindControl(click_location, terminal_window, which_control) <> 0 then
  496.                         begin
  497.                             if TrackControl(which_control, click_location, Ptr(-1)) = 1 then
  498.                                 begin
  499.                                     if which_control = break_button then
  500.                                         begin
  501.                                             ErrorHandler(SerSetBrk(aOutRefNum));
  502.                                             Delay(6, stop_time);
  503.                                             ErrorHandler(SerClrBrk(aOutRefNum));
  504.                                         end;
  505.                                     if which_control = help_button then
  506.                                         if Alert(aboutID, nil) = 1 then
  507.                                             ;
  508.                                 end;
  509.                         end;
  510.                 end;
  511.             otherwise
  512.                 begin
  513.                 end;
  514.         end; { case }
  515.     end; { CheckMousePosition }
  516.  
  517.   {--------------------------------------------------------------------------}
  518.  
  519.     procedure GetKeyboardChar;
  520.         var
  521.             key: char;
  522.             menu_ID: integer;
  523.             stop_time: LongInt;
  524.  
  525.     begin { GetKeyboardChar }
  526.         with current_event do
  527.             begin
  528.                 key := chr((LoWord(message)));{Lo}
  529.                 if BitAnd(modifiers, cmdKey) <> 0 then
  530.                     begin
  531.                         menu_choice := MenuKey(key);
  532.                         menu_ID := HiWord(menu_choice);
  533.                         Delay(30, stop_time);
  534.                         HiLiteMenu(menu_ID);
  535.                         HandleMenuChoice;
  536.                     end
  537.                 else
  538.                     begin
  539.                         this_char[1] := key;
  540.                         byte_count := 1;
  541.                         ErrorHandler(FSWrite(AOutRefNum, byte_count, @this_char));
  542.                     end;
  543.             end; { with }
  544.     end; { GetKeyboardChar }
  545.  
  546.   {--------------------------------------------------------------------------}
  547.  
  548.     procedure WriteScreenLine;
  549.  
  550.     begin { WriteScreenLine }
  551.         if Length(screen_line) > 0 then
  552.             begin
  553.                 HideTheCursor;
  554.                 DrawString(screen_line);
  555.                 xPos := xPos + Length(screen_line) * char_space;
  556.                 if xPos > right_limit then
  557.                     begin
  558.                         CarriageReturn;
  559.                         Linefeed;
  560.                     end;
  561.                 screen_line[0] := chr(0);
  562.                 InvertCursor;
  563.             end;
  564.     end; { WriteScreenLine }
  565.  
  566.   {--------------------------------------------------------------------------}
  567.  
  568.     procedure DoUpdate (anEvent: EventRecord);
  569.         var
  570.             savePort: GrafPtr;
  571.             theWindow: WindowPtr;
  572.     begin {DoUpdate}
  573.         theWindow := WindowPtr(anEvent.message);
  574.  
  575.         GetPort(savePort);
  576.         SetPort(theWindow);
  577.         BeginUpdate(theWindow);
  578. {Handle update events!}
  579. {If we had kept all text that has been drawn, we could redraw it!}
  580.  
  581. {Redraw buttons and the grow icon!}
  582.         DrawGrowIcon(theWindow);
  583.         DrawControls(theWindow);
  584.  
  585.         EndUpdate(theWindow);
  586.         SetPort(savePort);
  587.     end; {DoUpdate}
  588.  
  589.   {--------------------------------------------------------------------------}
  590.  
  591.     procedure CheckEventQueue;
  592.  
  593.     begin { CheckEventQueue }
  594.         SystemTask;
  595.         FlashCursor;
  596. {Minor flaw: Should use WaitNextEvent if available. /Ingemar}
  597.         if GetNextEvent(everyEvent, current_event) then
  598.             case current_event.what of
  599.                 mouseDown: 
  600.                     CheckMousePosition;
  601.                 keyDown, autoKey: 
  602.                     GetKeyboardChar;
  603. {Serious flaw: doesn't handle update events! /Ingemar}
  604.                 updateEvt: 
  605.                     DoUpdate(current_event);
  606.                 otherwise
  607.                     begin
  608.                     end;
  609.             end; { case }
  610.     end; { CheckEventQueue }
  611.  
  612.   {--------------------------------------------------------------------------}
  613.  
  614. begin { Serial }
  615.     InitializeUserInterface;
  616.     InitializeModemPort;
  617.     repeat
  618.         CheckEventQueue;
  619.         FlashCursor;
  620.         ErrorHandler(SerGetBuf(aInRefNum, byte_count));
  621.         if byte_count > 0 then
  622.             begin
  623.                 if byte_count > 64 then
  624.                     byte_count := 64;
  625.                 ErrorHandler(FSRead(aInRefNum, byte_count, @in_buffer));
  626.                 limit := byte_count;
  627.                 for index := 1 to limit do
  628.                     begin
  629.                         received_char := in_buffer[index];
  630.                         case ord(received_char) of
  631.                             control_G: 
  632.                                 begin
  633.                                     WriteScreenLine;
  634.                                     SysBeep(0);
  635.                                 end;
  636.                             control_H: 
  637.                                 begin
  638.                                     WriteScreenLine;
  639.                                     HideTheCursor;
  640.                                     xPos := xPos - char_space;
  641.                                     MoveTo(xPos, yPos);
  642.                                     DrawChar(' ');
  643.                                     MoveTo(xPos, yPos);
  644.                                 end;
  645.                             control_J: 
  646.                                 begin
  647.                                     WriteScreenLine;
  648.                                     Linefeed;
  649.                                 end;
  650.                             control_M: 
  651.                                 begin
  652.                                     WriteScreenLine;
  653.                                     CarriageReturn;
  654.                                 end;
  655.                             $20..$FF: 
  656.                                 begin
  657.                                     len := ord(screen_line[0]) + 1;
  658.                                     screen_line[0] := chr(len);
  659.                                     screen_line[len] := received_char;
  660.                                     if xPos + len * char_space > right_limit then
  661.                                         begin
  662.                                             WriteScreenLine;
  663.                                             CarriageReturn;
  664.                                             Linefeed;
  665.                                         end;
  666.                                 end;
  667.                             otherwise
  668.                                 begin
  669.                                 end;
  670.                         end; { case }
  671.                     end; { for }
  672.             end;
  673.         if Length(screen_line) > 0 then
  674.             WriteScreenLine;
  675.     until finished;
  676. {RAMSDClose(SPortA);}
  677.     if aInRefNum <> 0 then
  678.         if CloseDriver(aInRefNum) <> noErr then
  679.             ;
  680.     if aOutRefNum <> 0 then
  681.         if CloseDriver(aOutRefNum) <> noErr then
  682.             ;
  683.  
  684.     DisposeWindow(terminal_window);
  685. end.